/*
 * Label.java  0.4.0 / Oct 26, 2010
 *
 * Copyright (c) 2010 - 2011, cute4j.com and contributors.
 *
 * This software is licensed under the LGPL version 2.1 license.
 * A copy of this license is included in the file LICENSE-LGPL.txt.
 */
package com.cute4j.swing;

import com.cute4j.swing.properties.LabelProperties;

/**
 * Label Component.
 *
 * @cute4j.native
 *    generate="header"
 *
 * @author Slobodan Vrkacevic
 * @version 0.4.0
 */
public class Label extends Component
                   implements SwingConstants, LabelProperties {

// Public Static Fields. -------------------------------------------------------

  /**
   * Plain text format (the value is {@value}).
   */
  public static final int PLAIN_TEXT = 0;

  /**
   * Rich text format (the value is {@value}).
   */
  public static final int RICH_TEXT = 1;

  /**
   * Auto text format (the value is {@value}).
   */
  public static final int AUTO_TEXT = 2;

  /**
   * <tt>None</tt> border type (the value is {@value}).
   */
  public static final int BORDER_TYPE_NONE = 0;

  /**
   * <tt>Box</tt> border type (the value is {@value}).
   */
  public static final int BORDER_TYPE_BOX = 1;

  /**
   * <tt>Standard</tt> border type (the value is {@value}).
   */
  public static final int BORDER_TYPE_STANDARD = 2;

  /**
   * <tt>Classic</tt> border type (the value is {@value}).
   */
  public static final int BORDER_TYPE_CLASSIC = 3;

  /**
   * <tt>Styled</tt> border type (the value is {@value}).
   */
  public static final int BORDER_TYPE_STYLED = 6;

  /**
   * <tt>Plain</tt> border (the value is {@value}).
   */
  public static final int BORDER_STYLE_PLAIN = 16;

  /**
   * <tt>Raised</tt> border (the value is {@value}).
   */
  public static final int BORDER_STYLE_RAISED = 32;

  /**
   * <tt>Sunken</tt> border (the value is {@value}).
   */
  public static final int BORDER_STYLE_SUNKEN = 48;

// Static Initialization. ------------------------------------------------------

  static {
    _initialize();
  }

// Private Fields. -------------------------------------------------------------

  private String text;
  private int textFormat;
  private boolean wrapText;
  private int horizontalAlignment;
  private int verticalAlignment;
  private SwingIconSet iconSet;
  private int borderType;
  private int borderStyle;
  private int borderWidth;

// Public Constructors. --------------------------------------------------------

  /**
   * Constructs new Label object.
   */
  public Label() {
    this("", null, LEADING);
  }

  /**
   * Constructs new Label object.
   *
   * @param text the text
   */
  public Label(String text) {
    this(text, null, LEADING);
  }

  /**
   * Constructs new Label object.
   *
   * @param icon the icon
   */
  public Label(Icon icon) {
    this("", icon, LEADING);
  }

  /**
   * Constructs new Label object.
   *
   * @param text the text
   * @param icon the icon
   */
  public Label(String text, Icon icon) {
    this(text, icon, LEADING);
  }

  /**
   * Constructs new Label object.
   *
   * @param text the text
   * @param horizontalAlignment the horizontal alignment
   */
  public Label(String text, int horizontalAlignment) {
    this(text, null, horizontalAlignment);
  }

  /**
   * Constructs new Label object.
   *
   * @param text the text
   * @param icon the icon
   * @param horizontalAlignment the horizontal alignment
   */
  public Label(String text, Icon icon, int horizontalAlignment) {
    verticalAlignment = CENTER;
    this.horizontalAlignment = horizontalAlignment;
    textFormat = AUTO_TEXT;
    borderStyle = BORDER_STYLE_PLAIN;
    if (text != null) {
      this.text = text;
      _setText(_delegate, text); // NOPMD
    }
    if (icon != null) {
      iconSet = new SwingIconSet(this);
      _setIcon(_delegate, iconSet); // NOPMD
      iconSet.setIcon(icon, null);
      _setIconSize(_delegate, icon.getIconWidth(),
                   icon.getIconHeight()); // NOPMD
    }
  }

// Public Methods. -------------------------------------------------------------

  /**
   * Returns text.
   *
   * @return text
   */
  public String getText() {
    return text;
  }

  /**
   * Sets text.
   *
   * @param text the text
   */
  public void setText(String text) {
    final String oldText = this.text;
    if (oldText == null) {
      if (text == null) {
        return;
      }
    } else {
      if (oldText.equals(text)) {
        return;
      }
    }
    disposedCheck();
    _setText(_delegate, text);
    this.text = text;
    invalidate();
    firePropertyChange(PROPERTY_TEXT, oldText, text);
  }

  /**
   * Returns text format.
   *
   * @return text format
   */
  public int getTextFormat() {
    return textFormat;
  }

  /**
   * Sets text format.
   * <p>Valid values are: <tt>PLAIN_TEXT</tt>, <tt>RICH_TEXT</tt> and
   *                      <tt>AUTO_TEXT</tt>.
   * <br/>
   *   Default value is: <tt>AUTO_TEXT</tt>.
   * </p>
   *
   * @param textFormat the new text format
   */
  public void setTextFormat(int textFormat) {
    int oldTextFormat = this.textFormat;
    if (oldTextFormat != textFormat) {
      disposedCheck();
      this.textFormat = checkTextFormatKey(textFormat, "Invlid text format");
      _setTextFormat(_delegate, textFormat);
      firePropertyChange(PROPERTY_TEXT_FORMAT, oldTextFormat, textFormat);
    }
  }

  /**
   * Returns <tt>true</tt> if the label is wrapping text.
   *
   * @return <tt>true</tt> if the label is wrapping text
   */
  public boolean isWrapText() {
    return wrapText;
  }

  /**
   * Sets text wrap status.
   *
   * @param wrapText if <tt>true</tt> the label will wrap the text
   */
  public void setWrapText(boolean wrapText) {
    boolean oldWrapText = this.wrapText;
    if (oldWrapText != wrapText) {
      disposedCheck();
      _setWordWrap(_delegate, wrapText);
      this.wrapText = wrapText;
      firePropertyChange(PROPERTY_WRAP_TEXT, oldWrapText, wrapText);
    }
  }

  /**
   * Returns horizontal alignment.
   *
   * @return horizontal alignment
   */
  public int getHorizontalAlignment() {
    return horizontalAlignment;
  }

  /**
   * Sets horizontal alignment.
   * <p>Valid values are: <tt>LEFT</tt>, <tt>CENTER</tt>, <tt>RIGHT</tt>,
   *                      <tt>LEADING</tt> and <tt>TRAILING</tt>.
   * <br/>
   *   Default value is: <tt>LEADING</tt>.
   * </p>
   *
   * @param alignment the horizontal alignment
   */
  public void setHorizontalAlignment(int alignment) {
    int oldHorizontalAlignment = horizontalAlignment;
    if (oldHorizontalAlignment != alignment) {
      disposedCheck();
      horizontalAlignment = checkHorizontalKey(alignment,
                                               "Invlid horizontal alignment");
      _setAlignment(_delegate, alignment, verticalAlignment);
      firePropertyChange(PROPERTY_HORIZONTAL_ALIGNMENT, oldHorizontalAlignment,
                         alignment);
    }
  }

  /**
   * Returns vertical alignment.
   *
   * @return vertical alignment
   */
  public int getVerticalAlignment() {
    return verticalAlignment;
  }

  /**
   * Sets vertical alignment.
   * <p>Valid values are: <tt>TOP</tt>, <tt>CENTER</tt> and <tt>BOTTOM</tt>.
   * <br/>
   *   Default value is: <tt>CENTER</tt>.
   * </p>
   *
   * @param alignment the vertical alignment
   */
  public void setVerticalAlignment(int alignment) {
    int oldVerticalAlignment = verticalAlignment;
    if (oldVerticalAlignment != alignment) {
      disposedCheck();
      verticalAlignment = checkVerticalKey(alignment,
                                           "Invlid vertical alignment");
      _setAlignment(_delegate, horizontalAlignment, alignment);
      firePropertyChange(PROPERTY_VERTICAL_ALIGNMENT, oldVerticalAlignment,
                         alignment);
    }
  }

  /**
   * Returns icon.
   *
   * @return icon
   */
  public Icon getIcon() {
    if (iconSet != null) {
      return iconSet.getIcon();
    }
    return null;
  }

  /**
   * Sets icon.
   *
   * @param icon the icon
   */
  public void setIcon(Icon icon) {
    disposedCheck();
    if (icon == null) {
      if (iconSet != null) {
        iconSet.setIcon(null, PROPERTY_ICON);
        if (iconSet.isEmpty()) {
          _setIcon(_delegate, null);
          iconSet = null;
        }
      }
    } else {
      if (iconSet == null) {
        iconSet = new SwingIconSet(this);
        _setIcon(_delegate, iconSet);
      }
      iconSet.setIcon(icon, PROPERTY_ICON);
      _setIconSize(_delegate, icon.getIconWidth(), icon.getIconHeight());
    }
  }

  /**
   * Returns disabled icon.
   *
   * @return disabled icon
   */
  public Icon getDisabledIcon() {
    if (iconSet != null) {
      return iconSet.getDisabledIcon();
    }
    return null;
  }

  /**
   * Sets disabled icon.
   *
   * @param icon the disabled icon
   */
  public void setDisabledIcon(Icon icon) {
    disposedCheck();
    if (icon == null) {
      if (iconSet != null) {
        iconSet.setDisabledIcon(null, PROPERTY_DISABLED_ICON);
        if (iconSet.isEmpty()) {
          _setIcon(_delegate, null);
          iconSet = null;
        }
      }
    } else {
      if (iconSet == null) {
        iconSet = new SwingIconSet(this);
        _setIcon(_delegate, iconSet);
      }
      iconSet.setDisabledIcon(icon, PROPERTY_DISABLED_ICON);
      _setIconSize(_delegate, icon.getIconWidth(), icon.getIconHeight());
    }
  }

  /**
   * Returns border type.
   *
   * @return border type
   */
  public int getBorderType() {
    return borderType;
  }

  /**
   * Sets border type.
   *
   * @param borderType the border type
   */
  public void setBorderType(int borderType) {
    if ((borderType != BORDER_TYPE_NONE) && (borderType != BORDER_TYPE_BOX) &&
        (borderType != BORDER_TYPE_STANDARD) &&
        (borderType != BORDER_TYPE_CLASSIC) &&
        (borderType != BORDER_TYPE_STYLED)) {
      throw new IllegalArgumentException("Invalid border type");
    }
    final int oldBorderType = this.borderType;
    if (oldBorderType != borderType) {
      disposedCheck();
      _setBorderType(_delegate, borderType);
      this.borderType = borderType;
      firePropertyChange(PROPERTY_BORDER_TYPE, oldBorderType, borderType);
    }
  }

  /**
   * Returns border style.
   *
   * @return border style
   */
  public int getBorderStyle() {
    return borderStyle;
  }

  /**
   * Sets border style.
   *
   * @param borderStyle the border style
   */
  public void setBorderStyle(int borderStyle) {
    if ((borderStyle != BORDER_STYLE_PLAIN) &&
        (borderStyle != BORDER_STYLE_RAISED) &&
        (borderStyle != BORDER_STYLE_SUNKEN)) {
      throw new IllegalArgumentException("Invalid border style");
    }
    final int oldBorderStyle = this.borderStyle;
    if (oldBorderStyle != borderStyle) {
      disposedCheck();
      _setBorderStyle(_delegate, borderStyle);
      this.borderStyle = borderStyle;
      firePropertyChange(PROPERTY_BORDER_STYLE, oldBorderStyle, borderStyle);
    }
  }

  /**
   * Returns border width.
   *
   * @return border width
   */
  public int getBorderWidth() {
    return borderWidth;
  }

  /**
   * Sets border width.
   *
   * @param borderWidth int
   */
  public void setBorderWidth(int borderWidth) {
    if (borderWidth < 0) {
      throw new IllegalArgumentException("Invalid border width");
    }
    final int oldBorderWidth = this.borderWidth;
    if (oldBorderWidth != borderWidth) {
      disposedCheck();
      _setBorderWidth(_delegate, borderWidth);
      this.borderWidth = borderWidth;
      firePropertyChange(PROPERTY_BORDER_WIDTH, oldBorderWidth, borderWidth);
    }
  }

// Protected Methods. ----------------------------------------------------------

  /**
   * Checks horizontal alignment key.
   *
   * @param key the key
   * @param message the error message
   *
   * @return alignment key
   *
   * @throws IllegalArgumentException if the key is invalid
   */
  protected final int checkHorizontalKey(int key, String message) {
    if ((key == LEFT) || (key == CENTER) || (key == RIGHT) ||
        (key == LEADING) || (key == TRAILING)) {
      return key;
    }
    throw new IllegalArgumentException(message);
  }

  /**
   * Checks vertical alignment key.
   *
   * @param key the key
   * @param message the error message
   *
   * @return alignment key
   *
   * @throws IllegalArgumentException if the key is invalid
   */
  protected final int checkVerticalKey(int key, String message) {
    if ((key == TOP) || (key == CENTER) || (key == BOTTOM)) {
      return key;
    }
    throw new IllegalArgumentException(message);
  }

  /**
   * Checks text format key.
   *
   * @param key the key
   * @param message the error message
   *
   * @return alignment key
   *
   * @throws IllegalArgumentException if the key is invalid
   */
  protected final int checkTextFormatKey(int key, String message) {
    if ((key == PLAIN_TEXT) || (key == RICH_TEXT) || (key == AUTO_TEXT)) {
      return key;
    }
    throw new IllegalArgumentException(message);
  }

// Overridden Methods. ---------------------------------------------------------

  /**
   * {@inheritDoc}
   */
  public void updateLocalization() {
    super.updateLocalization();
    if (text != null) {
      _setText(_delegate, localizeString(text));
    }
  }

  /**
   * {@inheritDoc}
   */
  protected String paramString() {
    StringBuffer sb = new StringBuffer(super.paramString());
    if (text != null) {
      sb.append(",text=");
      sb.append(text);
    }
    return sb.toString();
  }

// Package-Private Native Methods. ---------------------------------------------

  native long _create();

  native void _setText(long delegate, String text);

  native void _setTextFormat(long delegate, int textFormat);

  native void _setWordWrap(long delegate, boolean wordWrap);

  native void _setAlignment(long delegate, int ha, int va);

  native void _setIcon(long delegate, SwingIconSet iconSet);

  native void _setIconSize(long delegate, int width, int height);

  native void _setBorderType(long delegate, int borderType);

  native void _setBorderStyle(long delegate, int borderStyle);

  native void _setBorderWidth(long delegate, int borderWidth);

// Private Static Native Method. -----------------------------------------------

  private static native void _initialize();

}
